#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>

void sig_quit(int signal)
{
    printf("have received SIGQUIT signal!\n");
}

int main(int argc, char const *argv[])
{
    // sigset_t 表示linux信号掩码集(信号集)
    sigset_t newmask, oldmask, pendmask;
    // 注册信号
    // 笔者说: "在商业代码中只用sigaction, 不使用signal"
    if (signal(SIGQUIT, sig_quit) == SIG_ERR) // signal函数,用于注册信号对应的信号处理函数,传入的是函数指针
    {
        printf("CANNOT capture SIGUSR signal\n");
        exit(-1);
    }

    sigemptyset(&newmask);        // sigemptyset 系统函数,用于清除信号集(全部置零)
    sigaddset(&newmask, SIGQUIT); // sigaddset 系统函数, 用于设定信号掩码,使后续信号无法收到

    // 重要::
    // 设置该进程所对应的信号集函数 sigprocmask
    // SIG_BLOCK表示设置进程新的信号屏蔽字为当前屏蔽字(系统在进程开始使为进程分配屏蔽字,开始时全部为零)和传入第二个参数(被我们设置为SIGQUIT屏蔽)的并集
    // 并且保存在第三个参数中,第三个参数用于保存没有生效之前的屏蔽集
    if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
    {
        printf("sigprocmask FAILED!\n");
        exit(-1);
    }
    else
    {
        printf("sigprocmask set success! Now SIG_QUIT not working...\n");
    }

    printf("sleep for 10sec......\n");
    sleep(10);
    printf("sleep ending......\n");

    // sigismember 检测信号集的特定位有没有被置位
    if (sigismember(&newmask, SIGQUIT))
    {
        printf("SIGQUIT have been shield!\n");
    }
    else
    {
        printf("SIGQUIT not been shield!\n");
    }

    if (sigismember(&newmask, SIGHUP))
    {
        printf("SIGHUP have been shield!\n");
    }
    else {
        printf("SIGHUP not been shield!\n");
    }

    // 现在需要取消对SIGQUIT信号的屏蔽, 将信号集还原
    // SIG_SETMASK 表示设定新的信号屏蔽字为第二个参数,第三个参数无效
    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
    {
        printf("sigprocmask FAILED!\n");
        exit(-1);
    }
    else
    {
        printf("sigprocmask set success!\n");
    }

    if (sigismember(&oldmask, SIGQUIT))
    {
        printf("SIGQUIT have been shield!\n");
    }
    else
    {
        printf("SIGQUIT not been shield! You can send SIGQUIT, sleeping for 10sec......\n");
        int my_sleep = sleep(10);
        if (my_sleep >0)
        {
            printf("mada mada... , last for %ds\n", my_sleep);
        }
    }

    printf("byebye!\n");

    return 0;
}

// aquawius@DESKTOP-CKR7QDI:~/C++CommunicationArchitecture/chapter3$ ./sigmask
// sigprocmask set success!
// sleep for 10sec......
// ^\^\^\^\^\^\sleep ending......
// SIGQUIT have been shield!
// SIGHUP not been shield!
// have received SIGQUIT signal!
// sigprocmask set success!
// SIGQUIT not been shield! You can send SIGQUIT, sleeping for 10sec......
// ^\have received SIGQUIT signal!
// mada mada... , last for 4s
// byebye!


// 虽然第一次等待后收到了SIGQUIT,当我们还原成老信号后，就相当于解除了对SIGQUIT信号的阻塞, 进程现在就已经能够收到SIGQUIT信号了
// 我发出了很多SIGQUIT的信号，进程却只收到了一个。这说明信号有等待机制(无法允许多个相同的信号排队等待), 其中五个SIGQUIT信号被合并成了一个，或者说其余四个信号被忽略了
// 还有一个函数叫做sigaction(), 用于替换signal()函数, 在商业代码中只用sigaction
